// SPDX-License-Identifier: GPL-2.0 or GPL-3.0
// Copyright © 2018-2019 Ariadne Devos
/* sHT -- keeping track of a stream's resources */

#include <stddef.h>
#include <sHT/compiler.h>
#include <sHT/paper.h>
#include <sHT/resource.h>
#include <sHT/stream.h>
#include <sHT/test.h>

_Bool
sHT_init_stream(struct sHT_objcache *papers, struct sHT_stream *stream)
{
	sHT_paper write_paper, read_paper;
	write_paper = sHT_alloc(papers);
	if (sHT_null_p(write_paper))
		goto enomem;
	read_paper = sHT_alloc(papers);
	if (sHT_null_p(read_paper))
		goto write_paper;

	*stream = (struct sHT_stream) {
		/* Try to provoke crashes when @code{stream->fd} is used before
		   initialisation. No one uses -2 for invalid file descriptors,
		   sHT uses it for undefined file descriptors (not the same
		   thing). */
		.fd = -2,
		.flags = 0,
		.to_write = {
			.first = write_paper,
			.offset = 0,
			.length = 0,
		},
		.has_read = {
			.first = read_paper,
			.offset = 0,
			.length = 0,
		},
	};
	sHT_depend(stream, write_paper);
	sHT_depend(stream, read_paper);
	_Bool ret = 0;
	sHT_depend(ret, stream);
	return ret;

write_paper:
	/* write_paper may speculatively be NULL, but sHT_free allows that. */
	sHT_free(papers, write_paper);
enomem:
	/* TODO: compile this out on release builds */
	/* Try to provoke a crash when @var{stream} is used, even though it is
	   uninitialised. */
	/* No one uses -2 for invalid file descriptors, sHT uses it for
	   undefined file descriptors (not the same thing). */
	stream->fd = -2;
	/* NULL papers in buffers of initialised structures are always
	   incorrect (in sHT, not necessarily elsewhere). So we can try to
	   provoke a segfault. */
	stream->has_read = stream->to_write = (struct sHT_buffer) {
		.first = NULL,
		.offset = 0,
		.length = sHT_PAPER_SIZE,
	};
	/* TODO: inform Valgrind of all this undefinedness with
	   VALGRIND_MAKE_MEM_UNDEFINED. */
	return 1;
}

void
sHT_free_stream(struct sHT_objcache *papers, struct sHT_stream *stream)
{
	sHT_free(papers, stream->has_read.first);
	sHT_free(papers, stream->to_write.first);
	/* TODO: consider tainting @var{stream}'s buffers, see
	   @var{sHT_init_stream}. */
}
